

'''
    梅森公式 计算链路传递函数
    @author: dushanchen
'''
import time
from pprint import pprint
from typing import OrderedDict


class Meson(object):
    
    def __init__(self, nodes, lines) -> None:
        self.__nodes = nodes
        self.__lines = lines
        self.__status = 'init'
        
        self.__ports = []               # 系统暴露的端口
        self.__routes = {}              # 所有前向通路
        self.__circles = {}             # 所有回路
        self.__delta = []               # 前向回路的余子式
        self.__delta_k = []             # 特征式
        self.__node_dict = {_['name']: _ for _ in nodes}           


    def __route(self):
        ''' 所有通路, 回路 '''
        
        roads = []   # 通路
        circles = [] # 回路

        for index, start in enumerate(self.__ports): # start : ('n1', 1)
            crosses = [] # 岔口
            
            road = [start + (0,)]
            crosses.append(road)

            while crosses:                         # 所有岔路
                road = crosses[0]

                end = road[-1]

                if end[2] == 0:         # 进入一个节点
                    end_name = end[0]
                    for port in range(self._get_node(end_name)['ports']):
                        out_port = (end_name, port, 1)
                        if out_port in road:
                            new_road = road.copy()
                            new_road.append(out_port)
                            circles.append(new_road)
                        else:
                            new_road = road.copy()
                            new_road.append(out_port)
                            crosses.append(new_road)  # 该节点的出口
                    del crosses[0]
                else:                   # 传出一个节点
                    next = self.__next_port( end[:2] )  # 下一个节点
                    if not next:
                        roads.append(road)     # 前向通路
                        del crosses[0]
                        continue
                    else:
                        next = next + (0, )
                        if next in road:       # 环  ( 判断一下传输率如果是0， 就不添加进去)
                            circles.append(road.copy().append(next))
                            del crosses[0]
                            continue
                        road.append(next)
                   
        for road in roads:
            key = f'{road[0]} -> {road[-1]}'
            if key not in self.__routes:
                self.__routes[key] = []
            self.__routes[key].append(road) 
        self.__circles = circles
           

    def _get_node(self, name):
        return self.__node_dict[name]

    def __next_port(self, port):
        for line in self.__lines:
            if port == line[:2]:
                return line[2:]
            if port == line[2:]:
                return line[:2]
        return None

    def __delta_(self) -> None:
        ''' 系统特征式'''
        pass
        self.__delta = []
        # [(2, 3,),(2, 5, 9),( 5, 6)]  回路的索引

    def __delta_k_(self, route):
        ''' 通路k 的余子式 '''
        self.__delta_k = []

    def add(self, nodes, lines):
        self.nodes = self.nodes.extends(nodes)
        self.lines = self.nodes.extends(lines)
        self.__analyze__()
    
    def update_matrix(self, nodes):
        pass
    
    def __get_ports(self):
        nodes = self.__nodes
        lines = self.__lines

        ports = OrderedDict({node['name']: [_ for _ in range(node['ports'])] for node in nodes})

        for line in lines:
            start_node, start_port = line[:2]
            end_node, end_port = line[2:]
            ports[start_node].remove(start_port)
            ports[end_node].remove(end_port)
        ports = [(p, _) for p, v in ports.items() for _ in v ]

        self.__ports = ports 
        print('ports: ', ports)
        # ports = [('n1', 0), ('n3', 1), ('n3', 3)]

    def __compute_route(self):
        pass

    def __compute_deltak(self):
        pass
    
    def __compute_t(self, route):
        trans = 1
        for r in range(len(route)/2):
            s = self._get_node(route[r*2])['s']
            start, end = route[r*2][1], route[r*2+1][1]
            trans = s[start][end]
        return trans

    def __analyze__(self):
        '''
            1. 找出系统的端口节点
            2. 拟定一个起点，终点
            3. 找出前向通路及 余子式，保存
            4. 找出回路及 特征式， 保存
            5. 换一个终点，循环2-4
        '''

        self.__get_ports()               # 系统暴露的端口 self.__ports
        self.__route()                   # 所有前向通路, 回路   self.__routes
        
        # self.__delta_k_()                # 前向回路的余子式
        # self.__delta_()                  # 特征式

        self.status = 'ready'

    def compute(self):
        ''' 
         E
            5. 传入s矩阵, 计算梅森公式，保存
            6. 循环每个端口节点，做上面的计算
        '''
        if self.__status != 'ready':
            self.__analyze__()
        pprint('roads: ')
        pprint(self.__routes)
        pprint('circles: ')
        pprint(self.__circles)
       
        # for routes in self.__routes:
        #     routes = self.__routes[f'']
        #     delta_k = self.__delta_k[f'']
            
        #     sum_p = sum(self.__compute_route(r) * self.__compute_deltak(d) for r, d in zip(routes, self.__delta_k))
        #     delta_value = self.__compute_delta()
        #     trans = sum_p / delta_value
        #     self.__matrix.append(trans)

if __name__ == '__main__':
    start = time.time()
    nodes = [
        {'name': 'n1', 'ports': 2, 'matrix':[[1+2j, 3-1j],[4-0.8j, 2+1j]]}, 
        {'name': 'n2',  'ports': 3, 'matrix':[[1+2j, 0, 3, 2j],[4-0.8j, 2+1j, 0+2j],[4-0.8j, 2+1j, 0+2j]]}, 
        {'name': 'n3',  'ports': 4, 'matrix':[[1+2j, 3-1j, 3, -1j],[0, 2+1j, 0+2j, 4-0.8j],[-0.8j, 2+1j, 0+2j, 0]]}, 
    ]
    lines = [('n1', 1, 'n2', 0), ('n2', 1, 'n3', 1), ('n2', 2, 'n3', 0)]
    # lines = [('n1', 1, 'n2', 0)]

    meson = Meson(nodes, lines)
    matrix = meson.compute()
    # print(matrix)
    print('use time: ', time.time() - start )